package group_safe_lru

import (
	"log"
	"sync"

	"bulgat.top/go_cache/safe_lru"
	"bulgat.top/go_cache/utils"
)

// A Group is a cache namespace and associated data loaded spread over
type Group struct {
	name   string
	getter Getter
	cache  *safe_lru.Cache
}

// A Getter loads data for a key.
type Getter interface {
	Get(key string) ([]byte, error)
}

// A GetterFunc implements Getter with a function.
type GetterFunc func(key string) ([]byte, error)

// Get implements Getter interface function
func (f GetterFunc) Get(key string) ([]byte, error) {
	return f(key)
}

var (
	lock   sync.RWMutex
	groups = make(map[string]*Group)
)

// NewGroup create a new instance of Group
func NewGroup(name string, capacity int64, getter Getter) *Group {
	if getter == nil {
		panic("[NewGroup] getter is nil")
	}
	lock.Lock()
	defer lock.Unlock()
	group := &Group{
		name:   name,
		getter: getter,
		cache:  safe_lru.New(capacity, nil),
	}
	groups[name] = group
	return group
}

// GetGroup returns the named group previously created with NewGroup, or
// nil if there's no such group.
func GetGroup(name string) *Group {
	lock.RLock()
	defer lock.RUnlock()
	return groups[name]
}

// Get value for a key from cache
func (g *Group) Get(key string) (safe_lru.ByteView, error) {
	if v, e := g.cache.Get(key); e {
		log.Println("[Get] cache hit")
		if b, ok := v.(safe_lru.ByteView); ok {
			return b, nil
		}
		return safe_lru.NewByteView(utils.ToBytes(v)), nil
	}
	return g.loadData(key)
}

// loadData loads data for a key from the getter and caches it. 回源函数
func (g *Group) loadData(key string) (safe_lru.ByteView, error) {
	bytes, err := g.getter.Get(key)
	if err != nil {
		return safe_lru.ByteView{}, err

	}
	b := safe_lru.NewByteView(bytes)
	g.cache.Put(key, b)
	return b, nil
}
